package com.quick.android.handler.http;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Map;

import org.json.JSONObject;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.android.volley.Response;
import com.quick.android.handler.http.impl.OnResponseListener;
import com.quick.android.handler.http.request.DownloadRequest;
import com.quick.android.handler.http.request.GsonRequest;
import com.quick.android.handler.http.request.UploadRequest;
import com.quick.android.utils.FileUtils;

import android.content.Context;

public class HttpHandler {
	private static HttpHandler instance;
	private RequestQueue mRequestQueue;
	private RequestQueue mUploadQueue;

	public static HttpHandler getInstance(Context context) {
		if (instance == null) {
			instance = new HttpHandler(context);
		}
		return instance;
	}

	private HttpHandler(Context context) {
		mRequestQueue = Volley.newRequestQueue(context.getApplicationContext());
	}

	/**
	 * get方式获取数据，数据经过gson转化为javaBean,在回调中获取
	 * 
	 * @param context
	 * @param url
	 * @param params
	 * @param clazz
	 * @param callback
	 */
	public <T> void getGsonData(Context context, String url,
			Map<String, String> params, Class<T> clazz,
			final OnResponseListener<T> callback) {
		getGsonData(context, url, null, params, clazz, callback);
	}

	/**
	 * get方式获取数据，数据经过gson转化为javaBean,在回调中获取
	 * 
	 * @param context
	 * @param url
	 * @param header
	 * @param params
	 * @param clazz
	 * @param callback
	 */
	public <T> void getGsonData(Context context, String url,
			Map<String, String> header, Map<String, String> params,
			Class<T> clazz, final OnResponseListener<T> callback) {
		httpGsonData(context, Method.GET, url, header, params, clazz, callback);
	}

	/**
	 * 发送get请求,返回的数据为String,需要自行处理
	 * 
	 * @param context
	 * @param url
	 * @param callback
	 */
	public void get(Context context, String url,
			final OnResponseListener<String> callback) {
		get(context, url, null, callback);

	}

	/**
	 * 发送get请求,返回的数据为String,需要自行处理
	 * 
	 * @param context
	 * @param url
	 * @param header
	 * @param callback
	 */
	public void get(Context context, String url,
			final Map<String, String> header,
			final OnResponseListener<String> callback) {
		StringRequest request = new StringRequest(Method.GET, url,
				new Response.Listener<String>() {
					@Override
					public void onResponse(String response) {
						callback.onSuccess(response);
					}
				}, new Response.ErrorListener() {
					@Override
					public void onErrorResponse(VolleyError error) {
						callback.onFailure(error.getMessage());
					}
				}) {

			@Override
			public Map<String, String> getHeaders() throws AuthFailureError {
				return header;
			}

		};
		request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
		request.setTag(context);
		mRequestQueue.add(request);
	}

	/**
	 * post请求数据，返回数据以javaBean格式返回
	 * 
	 * @param context
	 * @param url
	 * @param params
	 * @param clazz
	 * @param callback
	 */
	public <T> void postGsonData(Context context, String url,
			final Map<String, String> params, Class<T> clazz,
			final OnResponseListener<T> callback) {
		postGsonData(context, url, null, params, clazz, callback);
	}

	/**
	 * post请求数据，返回数据以javaBean格式返回
	 * 
	 * @param context
	 * @param url
	 * @param header
	 * @param params
	 * @param clazz
	 * @param callback
	 */
	public <T> void postGsonData(Context context, String url,
			final Map<String, String> header, final Map<String, String> params,
			Class<T> clazz, final OnResponseListener<T> callback) {
		httpGsonData(context, Method.POST, url, header, params, clazz, callback);
	}

	/**
	 * post请求数据，返回String数据
	 * 
	 * @param context
	 * @param url
	 * @param params
	 * @param callback
	 */
	public void post(Context context, String url,
			final Map<String, String> params,
			final OnResponseListener<String> callback) {
		post(context, url, null, params, callback);
	}

	/**
	 * 发送post请求
	 */
	public void post(Context context, String url,
			final Map<String, String> header, final Map<String, String> params,
			final OnResponseListener<String> callback) {
		StringRequest request = new StringRequest(Method.POST, url,
				new Response.Listener<String>() {
					@Override
					public void onResponse(String response) {
						callback.onSuccess(response);
					}
				}, new Response.ErrorListener() {
					@Override
					public void onErrorResponse(VolleyError error) {
						callback.onFailure(error.getMessage());
					}
				}) {

			@Override
			public Map<String, String> getHeaders() throws AuthFailureError {
				return header;
			}

			@Override
			protected Map<String, String> getParams() throws AuthFailureError {
				return params;
			}
		};
		request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 0, 1.0f));
		request.setTag(context);
		mRequestQueue.add(request);
	}

	/**
	 * 发送文件上传请求（适合小文件）
	 * 
	 */
	public void upload(Context context, String url, Map<String, String> params,
			Map<String, File> files,
			final OnResponseListener<JSONObject> callBack) {
		upload(context, url, null, params, files, callBack);
	}

	/**
	 * 发送文件上传请求（适合小文件）
	 * 
	 */
	public void upload(Context context, String url,
			final Map<String, String> header, final Map<String, String> params,
			final Map<String, File> files,
			final OnResponseListener<JSONObject> callBack) {
		UploadRequest request = new UploadRequest(Method.POST, url, null,
				new Response.Listener<JSONObject>() {

					@Override
					public void onResponse(JSONObject response) {
						callBack.onSuccess(response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						callBack.onFailure(error.getMessage());

					}
				}) {

			@Override
			public Map<String, File> getFileUploads() {
				return files;
			}

			@Override
			public Map<String, String> getStringUploads() {
				return params;
			}

			@Override
			public Map<String, String> getHeaders() throws AuthFailureError {
				return header;
			}
		};

		request.setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 0, 1.0f));
		request.setTag(context);
		mUploadQueue.add(request);
	}

	/**
	 * 文件下载（适合小文件）
	 * 
	 * @param context
	 * @param url
	 * @param path
	 * @param callBack
	 */
	public void download(Context context, String url, final String path,
			final OnResponseListener<File> callBack) {
		DownloadRequest request = new DownloadRequest(url, path,
				new Response.Listener<byte[]>() {
					@Override
					public void onResponse(byte[] response) {
						File file = saveFileFromBytes(path, response);
						callBack.onSuccess(file);
					}
				}, new Response.ErrorListener() {
					@Override
					public void onErrorResponse(VolleyError error) {
						callBack.onFailure(error.getMessage());
					}
				});
		request.setTag(context);
		mRequestQueue.add(request);
	}

	private File saveFileFromBytes(String path, byte[] bytes) {
		File file = null;
		if (bytes != null) {
			file = new File(path);
			InputStream stream = new ByteArrayInputStream(bytes);
			FileUtils.writeFile(file, stream);
		}
		return file;
	}

	/**
	 * 请求数据，以javaBean格式返回
	 * 
	 * @param context
	 * @param type
	 * @param url
	 * @param header
	 * @param params
	 * @param clazz
	 * @param callback
	 */
	private <T> void httpGsonData(Context context, int type, String url,
			final Map<String, String> header, final Map<String, String> params,
			Class<T> clazz, final OnResponseListener<T> callback) {
		GsonRequest<T> request = new GsonRequest<T>(type, url, clazz, header,
				params, new Response.Listener<T>() {

					@Override
					public void onResponse(T response) {
						callback.onSuccess(response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						callback.onFailure(error.getMessage());
					}
				});

		request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
		request.setTag(context);
		mRequestQueue.add(request);
	}

	/** 取消与context关联的所有请求 */
	public void cancelAllRequest(Context context) {
		mRequestQueue.cancelAll(context);
	}
}
